﻿using System;
using System.Diagnostics;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Mapping.ByCode;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Cfg.MappingSchema;

namespace DotNet.NH
{
    /// <summary>
    /// 数据库管理工具
    /// </summary>
    public static class DBFactory
    {
        private static readonly object m_SyncObject = new object();
        private static readonly Configuration m_Configuration = new Configuration();
        private static ModelMapper m_ModelMapper;
        private static ISessionFactory m_ISessionFactory;
        private static string m_ConnectionString;
        private static DBType m_DBType;

        #region 私有方法
        
        static DBFactory()
        {
            #region 从配置文件中读取数据

            var DBTypeStr = System.Configuration.ConfigurationManager.AppSettings["DBType"];

            if (string.IsNullOrEmpty(DBTypeStr))
                throw new InvalidOperationException("请在配置文件appSettings中配置数据库类型!key为\"DBType\",value为\"DBType枚举\"的字符串");

            m_DBType = (DBType)Enum.Parse(typeof(DBType), DBTypeStr);

            m_ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings[DBTypeStr].ConnectionString;

            if (string.IsNullOrEmpty(m_ConnectionString))
                throw new InvalidOperationException("请在配置文件connectionStrings中配置连接字符串!配置中的\"name\"与数据库类型配置中的\"value\"值相同");

            #endregion

            m_Configuration.SessionFactoryName(m_DBType.ToString());
            SetDialectAndDriver();
        }

        /// <summary>
        /// 设置数据库方言和驱动
        /// </summary>
        /// <param name="dataBaseIntegration"></param>
        private static void SetDialectAndDriver()
        {
            switch (m_DBType)
            {
                case DBType.SQLite:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<SQLiteDialect>();
                            db.Driver<SQLite20Driver>();
                        });
                        break;
                    }
                case DBType.MsSQLCE:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<MsSqlCe40Dialect>();
                            db.Driver<SqlServerCeDriver>();
                        });
                        break;
                    }
                case DBType.MsSql2000:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<MsSql2000Dialect>();
                            db.Driver<SqlClientDriver>();
                        });

                        break;
                    }
                case DBType.MsSql2005:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<MsSql2005Dialect>();
                            db.Driver<SqlClientDriver>();
                        });

                        break;
                    }
                case DBType.MsSql2008:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<MsSql2008Dialect>();
                            db.Driver<Sql2008ClientDriver>();
                        });

                        break;
                    }
                case DBType.Oracle10g:
                    {
                        throw new NotImplementedException("不会写!");
                    }
                case DBType.MySQL5:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<MySQL5Dialect>();
                            db.Driver<MySqlDataDriver>();
                        });

                        break;
                    }
                case DBType.MySQL:
                    {
                        m_Configuration.DataBaseIntegration(db =>
                        {
                            db.Dialect<MySQLDialect>();
                            db.Driver<MySqlDataDriver>();
                        });
                        break;
                    }
                case DBType.Oracle9i:
                    {
                        throw new NotImplementedException("不会写!");
                    }
                default:
                    break;
            }
        }

        /// <summary>
        /// 生成ISessionFactory,单例
        /// </summary>
        private static void BuildFactory(HbmMapping mapping)
        {
            if (m_ModelMapper == null)
            {
                throw new InvalidOperationException("请先调用SetModelMapper方法设置Model映射！"); 
            }
            m_Configuration.AddDeserializedMapping(mapping, null);
            if (m_ISessionFactory == null)
            {
                lock (m_SyncObject)
                {
                    if (m_ISessionFactory == null)
                    {
                        m_ISessionFactory = m_Configuration.BuildSessionFactory();
                    }
                }
            }
        }

        #endregion

        #region 公共方法
        
        /// <summary>
        /// 设置Model映射
        /// </summary>
        /// <param name="action"></param>
        public static void SetModelMapper(Action<ModelMapper> action)
        {
            m_ModelMapper = new ModelMapper();
            action(m_ModelMapper);
            var hbmMapping = m_ModelMapper.CompileMappingForAllExplicitlyAddedEntities();
            m_Configuration.AddMapping(hbmMapping);
            Debug.WriteLine(hbmMapping.AsString());
        }

        /// <summary>
        /// 打开新的会话
        /// </summary>
        public static ISession OpenSession()
        {
            //if (m_ISessionFactory == null)
            //    BuildFactory();
            //return m_ISessionFactory.OpenSession();
            return null;
        }

        /// <summary>
        /// 生成数据库
        /// </summary>
        public static void BuildSchema()
        {
            SchemaMetadataUpdater.QuoteTableAndColumns(m_Configuration);

            //创建数据库
            var sc = new SchemaExport(m_Configuration);
            sc.SetOutputFile(@"db.sql").Execute(false, false, false);
            sc.Create(false, true);
        }

        #endregion
    }
}
